//https://www.it610.com/article/1296519546370334720.htm
//https://zhuanlan.zhihu.com/p/107876873
//https://www.jianshu.com/p/bcfd7cc1c9f5
//useAsync需要管理我们的异步请求的过程，包括返回数据，loading状态，抛出错误
// useAsync需要帮我们useState去保存返回的结果，并允许我们手动修改结果
// useAsync需要自动去发送请求，除非我们要求它手动发送
// useAsync需要允许我们手动触发请求
import { DependencyList, useState ,useCallback,useRef} from "react"
import useMountedState from './useMountedState'
//type NameResolver = () => string;
type IFn<T,U extends any[]> = (...args : U)=> Promise<T>

type IOptions<Result> = {
  deps: DependencyList
  initialState: AsyncState<Result>
  successHandler?: (value: Result) => void
  errorHandler?: (error: Error) => void
}

type successState<T> = {
  loading: false
  error?: undefined
  value: T
}

type faliState = {
  loading: false
  error: Error
  value?: undefined
}

type loadingState = {
  loading: boolean
  error?: undefined
  value?: undefined
}

export type AsyncState<T> = successState<T> | faliState | loadingState
//https://www.zhihu.com/question/325412996
export type AsyncFn<Result = any, Args extends any[] = any[]> = [
  AsyncState<Result>,
  (...args: Args) => Promise<Result | null>,
]


// function identity<T>(arg: T): T {
//   return arg;
// }
export default function  useAsyncFn<Result = any ,Args extends any[] = any[]>(
  fn:IFn<Result,Args>,
  options: IOptions<Result> ={
    deps: [],
    initialState: { loading: false },
  }
) : AsyncFn<Result,Args>{
  const {deps=[] , initialState = { loading : false} , successHandler , errorHandler } = options
  //原来 useState() (prevState: undefined) => undefined”
  //解决 useState<AsyncState<Result>>()
  const [state,set] = useState<AsyncState<Result>>(initialState)
  const isMounted = useMountedState()
  // 记录是第几次调用
  const lastCallId = useRef(0);
  const callback =  useCallback((...args:Args)=>{
    const callId = ++lastCallId.current
    set({ loading: true })
    return fn(...args).then(
      (value)=>{
        if(isMounted()&& lastCallId.current){
          successHandler && successHandler(value)
          set({ value, loading: false })
        }
        return value
      },
    ).catch(
      (error) => {
        if (isMounted() && callId === lastCallId.current) {
          errorHandler && errorHandler(error)
          set({ error, loading: false })
        }
        return null
      },
    )
  },deps)
  // 原先  const [state,set] = useState<AsyncState<Result>>() 不能将类型“undefined”分配给类型“AsyncState<Result>”。ts(2322)
  // 解决 const [state,set] = useState<AsyncState<Result>>(initialState)
  return [state,callback]

}